原文題目
Given an integer array nums
of unique elements, return all possible subsets(the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
題目摘要
nums
,要求返回所有可能的子集(包含空子集)。Example 1:
Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
Example 2:
Input: nums = [0]
Output: [[],[0]]
解題思路一
result
。[]
加入 result
。backTracking
函式來生成所有可能的子集。backTracking
函式的主要目的是透過遞迴探索每一個元素的可能性,逐一列出所有子集。index
開始,逐個遍歷數組中的元素。nums[i]
加入到當前的子集 path
中,然後將這個 path
複製一份加入到 result
。backTracking
,進一步處理剩下的元素(從下一個索引開始),以生成更大的子集。path
中移除,恢復到上一層狀態,繼續探索其他可能的子集組合。result
中將包含所有可能的子集,包括空集、單個元素的子集、以及包含多個元素的子集。程式碼一
class Solution {
public List<List<Integer>> subsets(int[] nums) {
//創建一個儲存結果的陣列
List<List<Integer>> result = new ArrayList<>();
//一開始先將空集加入result
result.add(new ArrayList<>());
//呼叫backTracking函式
backTracking(0, nums, new ArrayList<>(), result);
return result;
}
private void backTracking(int index, int[] nums, List<Integer> path, List<List<Integer>> result){
for(int i=index; i<nums.length; i++){
path.add(nums[i]); //加入當前元素到path
result.add(new ArrayList<>(path)); //把當前的path加入結果陣列
//遞迴呼叫:將指標移至下一個元素並加入path
backTracking(i+1, nums, path, result);
//進行回溯:將最後一次放進path的元素移除
path.remove(path.size()-1);
}
}
}
解題思路二
result
來存儲所有的子集。subset
用來儲存當前的子集。findSubset
,參數包含數組 nums
、當前處理的索引 index
、結果集 result
和當前子集 subset
。index
等於數組長度,表示已經處理完所有元素,此時將 subset
複製並加入到 result
中,然後返回。nums[index]
加入到當前子集中。findSubset(nums, index + 1, result, subset)
。subset
中移除剛才加入的元素。findSubset(nums, index + 1, result, subset)
,這次不包括當前元素。result
。程式碼二
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> result = new ArrayList<>(); //設立結果的二維串列用來存儲所有子集
List<Integer> subset = new ArrayList<>(); //設立串列用來儲存當前子集
findSubset(nums, 0, result, subset);
return result;
}
//用來尋找所有子集的遞迴方法
private void findSubset(int[] nums, int index, List<List<Integer>> result, List<Integer> subset) {
//當前索引等於數組長度,表示已經處理完所有元素
if (index == nums.length) {
result.add(new ArrayList<>(subset));
return;
}
// 選擇當前元素加入到當前子集中,並進行下一步遞迴
subset.add(nums[index]);
findSubset(nums, index + 1, result, subset);
// 撤回選擇,移除當前數字,並遞迴檢查下一個數字
subset.remove(subset.size() - 1);
findSubset(nums, index + 1, result, subset);
}
}
結論
這題我和我的組員分別使用兩種解法,雖然都是利用遞迴來生成所有子集,但它們的實現方式有所不同。解法一是透過回溯法逐步將元素加入當前子集,並在每次遞迴中進行回溯來生成新的子集,結構上使用了for迴圈來控制遞迴的範圍,適合處理需要靈活控制的回溯問題。而解法二則是透過每個元素的二分選擇(包含或不包含當前元素)進行遞迴且沒有使用迴圈,適合處理需要遍歷所有選擇狀態的問題。整體而言,這兩種方法都能有效地解決問題,但根據具體需求,可以選擇不同的遞迴策略來生成子集。